﻿using System.Collections.ObjectModel;
using System.Threading.Channels;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using MeterReader.Common.Extensions;
using MeterReader.Messages;
using MeterReader.Models;
using MeterReader.Services.Repositories;
using Microsoft.Extensions.Logging;

namespace MeterReader.Services
{
    public partial class SimDBReadService : ObservableObject, IDataService
    {
        private readonly ILogger<SimDBReadService> _logger;
        private readonly IReadRepository _meterReadRepository;
        private readonly IWriteDbRepository _meterWriteRepository;
        private ObservableCollection<MeterDataCollection> _collection = new();
        private CancellationTokenSource _cancellationTokenSource = new();
        private Channel<TableMeters> _channel = Channel.CreateUnbounded<TableMeters>();

        public SimDBReadService(ILogger<SimDBReadService> logger, IReadRepository meterReadRepository, IWriteDbRepository meterWriteRepository)
        {
            _logger = logger;
            _meterReadRepository = meterReadRepository;
            _meterWriteRepository = meterWriteRepository;
        }

        [ObservableProperty]
        private bool _working = false;

        partial void OnWorkingChanged(bool value)
        {
            WeakReferenceMessenger.Default.Send(new WorkStatusMessage(value));
        }

        /// <summary>
        /// 开始采集数据
        /// </summary>
        public async void StartPeriodicRead()
        {
            _logger?.LogInformation("开始读取数据...");
            Working = true;
            await Task.Delay(1);
            try
            {
                while (!_cancellationTokenSource.Token.IsCancellationRequested)
                {
                    // 读取数据
                    await ReadAsync().WaitAsync(TimeSpan.FromSeconds(2));
                    // 等待 1 秒钟
                    await Task.Delay(1000, _cancellationTokenSource.Token);
                    // 写入数据库
                    await WriterAsync().WaitAsync(TimeSpan.FromSeconds(2));
                }
            }
            catch (OperationCanceledException ex)
            {
                StopPeriodicRead();
                _logger?.LogInformation($"停止读取数据：{ex.Message}");
            }
            catch (TimeoutException ex)
            {
                StopPeriodicRead();
                string message = $"读取数据超时：{this.GetType().FullName}：{ex.Message}{Environment.NewLine}Inner Exception: {ex.InnerException?.Message}";
                _logger!.LogError(message);
                WeakReferenceMessenger.Default.Send(new FaultMessage(message));
            }
            catch (Exception ex)
            {
                StopPeriodicRead();
                string message = $"读取数据异常：{this.GetType().FullName}：{ex.Message}{Environment.NewLine}Inner Exception: {ex.InnerException?.Message}";
                _logger!.LogError(message);
                WeakReferenceMessenger.Default.Send(new FaultMessage(message));
            }
        }

        /// <summary>
        /// 停止采集数据
        /// </summary>
        public void StopPeriodicRead()
        {
            _cancellationTokenSource.Cancel();
            _cancellationTokenSource = new CancellationTokenSource();
            Working = false;
        }

        /// <summary>
        /// 获取View绑定的集合
        /// </summary>
        /// <returns>View绑定的集合</returns>
        public ObservableCollection<MeterDataCollection> GetMeterDataCollections() => _collection;

        private async Task ReadAsync()
        {
            await _meterReadRepository.ReadDataAsync(
                (t) =>
                {
                    _channel.Writer.WriteAsync(t, _cancellationTokenSource.Token);
                    _collection.AddNewMeterDataCollection(t); // 更新 UI
                },
                _cancellationTokenSource.Token
            );
        }

        private async Task WriterAsync()
        {
            await _channel.Reader.WaitToReadAsync(_cancellationTokenSource.Token);
            var tableMeters = await _channel.Reader.ReadAsync(_cancellationTokenSource.Token);
            tableMeters.Date = DateTime.Now;
            tableMeters.ID = 0; // 主键不能重复
            await _meterWriteRepository.WriteDataAsync(tableMeters, _cancellationTokenSource.Token);
        }
    }
}
